#include "Controller.h"
#include "XmlReader.h"

#include "ConferenceModule.h"

using namespace std;
using namespace resip;

Controller::Controller() : m_registerModule(0), m_dialogUsageManager(0), m_masterProfile(0), 
m_clientAuthManager(0), m_keepAliveManager(0), m_userInterface(0)
{
	initialize();
}

Controller::~Controller()
{
	cleanup();
}

void Controller::initialize()
{
	// Create all managers

	createManagers();

	// Create UserInterface

	createUserInterface();
	
	// Initialize all managers

	initializeManagers(); 

	// Initialize all modules

	initializeModules();

	// Initialize loggers

	Log::initialize(Log::File, resip::Log::Warning, "IM", "log.txt");
	Log::initialize(Log::File, resip::Log::Debug, "IM", "log.txt");
	Log::initialize(Log::File, resip::Log::Info, "IM", "log.txt");

	initializeConference();
}

void Controller::initializeConference()
{
	m_sendModule = new ConferenceModule;
	m_receiveModule = new ConferenceModule;

	m_sendModule->setMode(1);
	m_receiveModule->setMode(2);

	m_sendModule->setBasePort(4000);
	m_sendModule->setPort(4010);

	m_receiveModule->setBasePort(5010);
	m_receiveModule->setPort(5000);

	uint8_t m_ip[4] = {127,0,0,1};

	m_sendModule->setIp(m_ip);
	m_sendModule->setIp(m_ip);
	

	//m_sendModule->start();


}

void Controller::cleanup()
{
}

void Controller::start(string config, string codecs)
{
	// Start session timer

	m_userInterface->startTimers();

	// Read the configfile

	readConfigFile(config);

	// Read the codecFile

	m_sdpModule->readCodecFile(codecs);
	initializeSdpContent();

	// Add contactList

	initializeUserInterface();

	// Register ourself

	registerOurself();

	// See who's online

	findOnlineContacts();
}

void Controller::checkForResponse()
{
	m_sessionModule->waitForSessionResponse();
}

void Controller::changeContactStatus(string contact, bool online)
{
	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		if( m_sessionData.contacts[i]->user == contact )
		{
			m_sessionData.contacts[i]->online = online;
			m_userInterface->changeContactStatus(m_sessionData.contacts[i]->nick.c_str(), online);
		}
	}
}

void Controller::sentMessage(string message)
{
	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		string user = m_sessionData.contacts[i]->user;
		bool online = m_sessionData.contacts[i]->online;

		if( online )
		{
			m_sessionModule->setDestUser(user);
			m_sessionModule->sendRegularMessage(message);			
		}
	}
}

void Controller::messageReceived(string contact, string message)
{
	if( message != "<:STATUS_CHECK:>" )
	{
		string nick = contactToNick(contact);
		m_userInterface->addMessage(nick.c_str(), message.c_str());

		messageSucceeded(contact); // MOET NOG VERANDEREN!!!
	}
}

void Controller::messageSucceeded(string contact)
{
	ContactData* contactData = findContact(contact);

	if( contactData )
	{
		if( !contactData->online )
		{
			contactData->online = true;
			changeContactStatus(contact, true);
		}
	}
}

void Controller::inviteSelectedContact()
{
	// Find the desired contact

	string nick = m_userInterface->getSelectedNickName();
	string contact = nickToContact(nick);
	ContactData* contactData = findContact(contact);

	// If contact found

	if( contactData )
	{
		//MAARTEN
		if( contactData->online )
		{
			// Set the destination

			m_sessionModule->setDestUser(contactData->user);

			// Sent the message

			string sdp = m_sdpModule->createSdpOffer();

			//MAARTEN
			m_sessionModule->sendInviteMessage(sdp);
		}

		else
			m_userInterface->showInformationDialog("Information", "Selected contact not online!");
	}

	// If no contact found

	else
		m_userInterface->showWarningDialog("Warning", "Please, select contact!");
}

void Controller::shutDown()
{
	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		ContactData* data = m_sessionData.contacts[i];

		m_sessionModule->setDestUser(data->user);
		m_sessionModule->sendByeMessage();
	}

	m_sessionModule->shutDown();

	exit(0);
}

void Controller::createManagers()
{
	// Create SipStack

	m_stack = new SipStack();

	// Create DialogUsageManager

	m_dialogUsageManager = new DialogUsageManager(*m_stack);

	// Create MasterProfile

	m_masterProfile = new SharedPtr<MasterProfile>( new MasterProfile() );

	// Create ClientAuthenticationManger

	m_clientAuthManager = new auto_ptr<ClientAuthManager>( new ClientAuthManager() );

	// Create KeepAliveManager

	m_keepAliveManager = new auto_ptr<KeepAliveManager>( new KeepAliveManager() );

	// Create ClientAppDialogSetManager

	m_clientAppDialogSetFactory = new auto_ptr<AppDialogSetFactory>( new ClientAppDialogSetFactory() );
}

void Controller::createUserInterface()
{
	m_userInterface = new MainWindow("Instant Messenger v1.0", this);
	m_userInterface->show();
}

void Controller::initializeManagers()
{
	// Initialize ClientAuthenticationManager

	initializeClientAuthManager();

	// Initialize ClientAppDialogSetFactory

	initializeClientAppDialogSetFactory();
}

void Controller::initializeModules()
{
	// Initialize RegisterModule

	m_registerModule = new RegisterModule(m_dialogUsageManager, m_stack);

	// Initialize OptionsModule

	m_optionsModule = new OptionsModule(m_dialogUsageManager, m_stack);

	// Initialize SessionModule

	m_sessionModule = new SessionModule(m_dialogUsageManager, m_stack, this);

	// Initialize SdpModule

	m_sdpModule = new SdpModule();
}

void Controller::initializeClientAuthManager()
{
	m_dialogUsageManager->addTransport(UDP, BASEPORT, V4);

	m_dialogUsageManager->setClientAuthManager( (*m_clientAuthManager) );
	m_dialogUsageManager->setKeepAliveManager( (*m_keepAliveManager) );
	m_dialogUsageManager->setMasterProfile( (*m_masterProfile) );
	m_dialogUsageManager->getMasterProfile()->setDefaultRegistrationTime(REG_TIME);
	m_dialogUsageManager->getMasterProfile()->addSupportedMethod(MESSAGE);
	m_dialogUsageManager->getMasterProfile()->addSupportedMimeType(MESSAGE, Mime("text", "plain"));
}

void Controller::initializeClientAppDialogSetFactory()
{
	m_dialogUsageManager->setAppDialogSetFactory(*m_clientAppDialogSetFactory);
}

void Controller::initializeUserInterface()
{
	// Connect callBacks

	QObject::connect(m_userInterface->m_sendButton, SIGNAL(clicked()), m_userInterface, SLOT(sentMessage()));
	QObject::connect(m_userInterface->m_sessionTimer, SIGNAL(timeout()), m_userInterface, SLOT(sessionTimeout()));
	QObject::connect(m_userInterface->m_statusTimer, SIGNAL(timeout()), m_userInterface, SLOT(statusTimeout()));

	// Add contacts to contactList

	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
		m_userInterface->addContact(m_sessionData.contacts[i]->nick.c_str(), m_sessionData.contacts[i]->online);
}

void Controller::initializeSdpContent()
{
	m_sdpModule->setVersion(0);

	m_sdpModule->setUsername(m_sessionData.user);
	m_sdpModule->setSessionId("2890844526");
	m_sdpModule->setSessionVersion("2890842807");
	m_sdpModule->setBaseIP(m_dialogUsageManager->getHostAddress().c_str());

	m_sdpModule->setSessionName("IMv1.0"); // MOET NOG EEN SPECIFIEKE NAAM KRIJGEN

	m_sdpModule->setStartTime(0);
	m_sdpModule->setStopTime(0);

	m_sdpModule->setMediaIP(m_dialogUsageManager->getHostAddress().c_str());

	m_sdpModule->setAudioPort(BASE_AUDIO_PORT);
	m_sdpModule->setVideoPort(BASE_VIDEO_PORT);
}

void Controller::readConfigFile(string file)
{
	XmlReader reader;
	reader.parseConfigFile(file, m_sessionData);
}

void Controller::registerOurself()
{
	m_registerModule->setDestHost(m_sessionData.server);
	m_registerModule->setDestPassword(m_sessionData.password);
	m_registerModule->setDestUser(m_sessionData.user);
	m_registerModule->setScheme("sip");

	m_registerModule->sendRegisterMessage();
}

void Controller::findOnlineContacts()
{
	m_sessionModule->setDestHost(m_sessionData.server);
	m_sessionModule->setDestPassword(m_sessionData.password);
	m_sessionModule->setScheme("sip");
	m_sessionModule->setBaseUser(m_sessionData.user);

	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		string contact = m_sessionData.contacts[i]->user;

		checkContactStatus(contact);
	}
}

void Controller::checkContactStatus(string contact)
{
	m_sessionModule->setDestUser(contact);
	m_sessionModule->sendRegularMessage("<:STATUS_CHECK:>");
}

string Controller::contactToNick(string contact)
{
	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		if( contact == m_sessionData.contacts[i]->user )
			return m_sessionData.contacts[i]->nick;
	}

	return string("unknown");
}

string Controller::nickToContact(string nick)
{
	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		if( nick == m_sessionData.contacts[i]->nick )
			return m_sessionData.contacts[i]->user;
	}

	return string("unknown");
}

ContactData* Controller::findContact(string contact)
{
	for( int i=0 ; i < m_sessionData.contacts.size() ; ++i )
	{
		if( contact == m_sessionData.contacts[i]->user )
			return m_sessionData.contacts[i];
	}

	return 0;
}